package com.li.onjava8.concurrent.under.collection;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * DelayQueue
 * 这是一个无界阻塞队列 （ BlockingQueue ），用于放置实现了 Delayed 接口的对象，其中的对象只能
 * 在其到期时才能从队列中取走。这种队列是有序的，因此队首对象的延迟到期的时间最长。如果没有任
 * 何延迟到期，那么就不会有队首元素，并且 poll() 将返回 null
 */
class DelayedTask implements Runnable, Delayed {
    private static int counter = 0;
    private final int id = counter++;
    private final int delta;
    private final long trigger;
    //输入顺序
    protected static List<DelayedTask> sequence = new ArrayList<>();
    public DelayedTask(int delayInMilliseconds) {
        delta = delayInMilliseconds;
        trigger = System.nanoTime() + TimeUnit.NANOSECONDS.convert(delta, TimeUnit.MILLISECONDS);
        sequence.add(this);
    }

    /**
     * 该方法用来告知延迟到期有多长时间，或者延迟在多长时间之前已经到期了
     * @param unit the time unit
     * @return
     */
    @Override
    public long getDelay(TimeUnit unit) {
        return unit.convert(
                trigger - System.nanoTime(),
                TimeUnit.NANOSECONDS);
    }

    /**
     * 为了排序， Delayed 接口还继承了 Comparable 接口，因此必须实现 compareTo(),使其可以产生合理的比较。
     * @param arg the object to be compared.
     * @return
     */
    @Override
    public int compareTo(Delayed arg) {
        DelayedTask that = (DelayedTask) arg;
        if (trigger < that.trigger) return -1;
        if (trigger > that.trigger) return 1;
        return 0;
    }
    @Override
    public void run() {
        System.out.println(this + " ");
    }

    @Override
    public String toString() {
        return String.format("[%d] Task %d", delta, id);
    }
    public String summary() {
        return String.format("(%d:%d)", id, delta);
    }

    public static class EndTask extends DelayedTask {
        public EndTask(int delay) {
            super(delay);
        }
        @Override
        public void run() {
            sequence.forEach(dt ->
                    System.out.println(dt.summary()));
        }
    }
}

public class DelayQueueDemo {
    public static void main(String[] args) throws InterruptedException {
        //生成20个DelayedTask加一个EndTask，放入DelayQueue
        DelayQueue<DelayedTask> tasks = Stream.concat(
                new Random(47).ints(20, 0, 4000)
                        .mapToObj(DelayedTask::new),
                Stream.of(new DelayedTask.EndTask(4000))
        ).collect(Collectors.toCollection(DelayQueue::new));
        while (tasks.size() > 0)
            tasks.take().run();
    }

}
